<template>
  <el-upload
    ref="upload"
    action="#"
    :before-upload="beforeUpload"
    :http-request="handleRequest"
    :multiple="true"
    :limit="limit"
    :drag="drag"
    :disabled="disabled"
    :on-exceed="handleExceed"
    :file-list="fileList"
    :auto-upload="true"
    :class="`${disabled ? 'el-upload-disabled' : drag ? 'el-upload-drag-outer' : ''}`"
  >
    <slot name="btn">
      <t-button v-if="!drag" className="uploadClass" svgIcon="ic-upload" :disabled="disabled">点击上传</t-button>
      <div v-else>
        <img src="@/assets/images/file_upload_icon.png" class="mx-auto !mb-[17px] !mt-[24px] h-[48px]" />
        <div class="text-[16px] font-normal leading-[24px] text-[#515A6E]">点击或将文件拖拽到这里上传</div>
        <div slot="tip" class="mt-[4px] text-[14px] font-normal leading-[20px] text-[#7E8A9D]">
          <span v-if="accept.length"
            >支持上传{{ accept.join("、") }}等格式且不大于<b>{{ size }}</b
            >MB, 最多可上传<b>{{ limit }}</b
            >个附件</span
          >
          <span v-else>最多可上传{{ limit }}个附件，每个附件限制{{ size }}MB以下，格式不限</span>
        </div>
      </div>
    </slot>
    <div v-if="!drag" slot="tip">
      <slot name="tip">
        <div class="el-upload__tip text-[12px] text-[#7E8A9D]">
          <span v-if="accept.length"
            >支持上传{{ accept.join("、") }}等格式且不大于<b>{{ size }}</b
            >MB, 最多可上传<b>{{ limit }}</b
            >个附件</span
          >
          <span v-else>最多可上传{{ limit }}个附件，每个附件限制{{ size }}MB以下，格式不限</span>
        </div>
      </slot>
    </div>
    <div slot="file" slot-scope="{ file }">
      <div class="flex flex-row items-center">
        <span v-if="file?.attUrl" class="el-icon-success mr-[4px]" style="color: #078d5c"></span>
        <span v-if="file?.attUrl" class="mr-[4px] h-[8px] w-[1px] bg-[#E8EAEF]"></span>
        <img :src="require(`@/assets/images/${getIconByFile(file?.originalName || file.name)}.svg`)" />
        <el-tooltip
          effect="dark"
          :content="file.originalName || file.name"
          placement="top"
          :disabled="file.originalName?.length > 22 || file.name?.length > 22 ? false : true"
        >
          <div class="fileName ml-[8px] flex-1 leading-[24px]">
            {{ file.originalName || file.name }}
          </div>
        </el-tooltip>
        <SvgIcon
          v-if="showButtons.includes('download') && file.id"
          name="file_download"
          class="mr-[8px] cursor-pointer text-[16px]"
          @click="handleDownload(file)"
        />
        <SvgIcon
          v-if="showButtons.includes('preview') && file.id && canPreview(file.attUrl)"
          name="file_preview"
          class="mr-[8px] cursor-pointer text-[16px]"
          @click="kkFileView(file.attUrl)"
        />
        <SvgIcon
          v-if="showButtons.includes('delete') && !disabled"
          name="file_delete"
          class="mr-[8px] cursor-pointer text-[16px]"
          @click="handleRemove(file)"
        />
      </div>
      <!-- 进度条 -->
      <el-progress
        v-if="file.percentage < 100"
        :percentage="file.percentage"
        :show-text="false"
        :stroke-width="3"
        style="top: 26px"
      ></el-progress>
    </div>
  </el-upload>
</template>

<script>
import axios from "axios";
import { clone } from "xe-utils";
import preview from "@/mixin/preview";
import fileIcon from "@/mixin/fileIcon";
import exportBlob from "@/util/exportBlob";
import { systemUploadFile, systemDeleteFile } from "@/api/file";
import { kkFileView, canPreview } from "@/util/kkview";

export default {
  name: "FileUploadBtn",
  mixins: [preview, fileIcon],
  model: {
    prop: "value",
    event: "change",
  },
  props: {
    value: {
      type: Array,
      default: () => {
        return [];
      },
    },
    limit: {
      type: Number,
      default: 100,
    },
    // 文件大小多少兆 MB
    size: {
      type: Number,
      default: 200,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * 接受文件类型，默认所有类型
     * 例如 ['jpg', 'png']
     */
    accept: {
      type: Array,
      default: () => {
        return [];
      },
    },
    showButtons: {
      type: Array,
      default: () => {
        return ["download", "preview", "delete"];
      },
    },
    drag: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      // 文件列表
      fileList: [],
    };
  },
  watch: {
    value: {
      handler() {
        this.fileList = this.value ? clone(this.value, true) : [];
      },
      immediate: true,
    },
  },
  methods: {
    kkFileView,
    canPreview,
    async handleRemove(file) {
      try {
        await this.$confirm("确定删除此文件?", "操作确认", {
          confirmButtonText: "确 定",
          cancelButtonText: "取 消",
          type: "warning",
        });
        if (file.id) {
          systemDeleteFile({ id: file.id }).then((data) => {
            this.$message.success("删除成功");
            this.fileList = this.fileList.filter((row) => {
              return row.id !== file.id;
            });
            this.onChange();
          });
        } else {
          // 取消请求
          file.cancel(`「${file.name}」已取消上传`);
          const _index = this.fileList.findIndex((row) => {
            return row.uid === file.uid;
          });
          this.fileList.splice(_index, 1);
        }
      } catch {
        this.$message.warning("已取消删除");
      }
    },
    // 文件超出个数限制时
    handleExceed(files, fileList) {
      this.$message.warning(
        `当前限制选择 ${this.limit} 个文件，本次选择了 ${files.length} 个文件，共选择了 ${
          files.length + fileList.length
        } 个文件`,
      );
    },
    handleSuccess(response, file) {
      this.fileList = this.fileList.map((v) => {
        if (v.uid === file.uid) {
          return response;
        }
        return v;
      });
      this.onChange();
    },
    // 返回 false 或者返回 Promise 且被 reject，则停止上传
    beforeUpload(file) {
      const _name = file.name.split(".");
      const fileType = _name[_name.length - 1];
      if (this.accept.length && !this.accept.includes(fileType.toLowerCase())) {
        this.$message.error(`文件「${file.originalName || file.name}」格式错误，无法继续上传`);
        return false;
      }
      if (file.size <= 0) {
        this.$message.error(`文件「${file.originalName || file.name}」内容为空，无法继续上传`);
        return false;
      }
      if (file.size / 1024 / 1024 > this.size) {
        this.$message.error(`文件「${file.originalName || file.name}」大小超过${this.size}MB，无法继续上传`);
        return false;
      }
      return true;
    },
    onChange() {
      const list = clone(this.fileList, true);
      this.$emit("change", list);
    },
    handleDownload(file) {
      exportBlob({ params: { id: file.id } });
    },
    // 自定义上传实现，多文件上传有延迟
    async handleRequest(param) {
      const that = this;
      const { file } = { ...param };
      try {
        const fileItem = {
          name: file.name,
          percentage: 0,
          raw: file,
          size: file.size,
          status: "",
          uid: file.uid,
          // 定义取消请求
          cancel: null,
        };
        this.fileList.push(fileItem);

        const formData = new FormData();
        formData.append("file", param.file);
        try {
          // 上传文件
          const data = await systemUploadFile(formData, {
            onUploadProgress(progress) {
              const percent = Math.floor((progress.loaded / progress.total) * 100);
              fileItem.percentage = percent;
            },
            cancelToken: new axios.CancelToken(function executor(c) {
              fileItem.cancel = c;
            }),
          });
          if (data && data.length) {
            this.handleSuccess(data[0], fileItem);
          }
        } catch {
          console.log("err");
        }
      } catch {
        this.$message.warning("上传失败");
      }
    },
    handleProgress(event, file) {},
    // 取消所有未上传完成的文件，需要关闭弹窗时手动调用
    cancelFile() {
      this.fileList.forEach((file) => {
        if (file.cancel) {
          file.cancel();
        }
      });
    },
    // 验证文件是否上传完成
    validForm() {
      const isOver = this.fileList.every((v) => {
        return v.id;
      });
      if (!isOver) {
        this.$message.error("有文件未上传完成，请等待上传完成");
        return false;
      }
      return true;
    },
  },
};
</script>

<style lang="scss" scoped>
:deep(.el-upload-dragger) {
  width: 368px;
  height: 180px;
  padding: 0 28px;
  background: #fafbfc;
  border: 1px dashed #bac3d3;
  border-radius: 4px;
}

:deep(.el-upload-list__item) {
  width: 368px;
}

.fileName {
  height: 24px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.el-upload-drag-outer {
  line-height: 0;
}
</style>
